/**
 * Copyright (C) 2011-2012 GreenSoft S.A.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.jeecommons.web.jsf;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.Conversation;
import javax.inject.Inject;

import ar.com.greensoft.jeecommons.web.CrudFacade;
import ar.com.greensoft.jeecommons.web.jsf.util.FacesUtil;
import ar.com.greensoft.jeecommons.web.jsf.util.JSFMenuUtil;
import ar.com.greensoft.neosystem.crm.web.beans.NavigationConstants;
import ar.com.greensoft.neosystem.dao.DaoException;
import ar.com.greensoft.neosystem.dao.GenericDao;
import ar.com.greensoft.neosystem.model.GsEntity;

/**
 * 
 * @author Jorge E. Villaverde
 * @date 16/08/2012
 * @version 1.0.0
 */
public abstract class AbstractConversationCrudFacadeBean<T extends GsEntity, PK extends Serializable> 
	implements CrudFacade<T>, Serializable, NavigationConstants{

	/**
	 * 
	 */
	private static final long serialVersionUID = -2546277308034956455L;
	@Inject
	protected Logger logger;

	private PK id;
	
	private T entity;
	
	@Inject
	private Conversation conversation;	

    /**
     * Cancel View
     */
    protected String cancelView;
    
    /**
     * Return View
     */
    protected String persistReturnView;
	
//	@PostConstruct
//	public void initBean() {
////		searchResultsCount = -1;
////		editing = false;
//		setEntity(newEntity());
//	}
	
	
	@Override
	public T getEntity() {
		if (this.entity == null) {
			if (this.id != null) {
				this.entity = loadEntity();
			} else {
				this.entity = newEntity();
			}
		}
		return this.entity;
	}
	
	public void setEntity(T entity) {
		this.entity = entity;
	}

	public PK getId() {
		return this.id;
	}


	public void setId(PK id) {
		this.id = id;
	}

	public boolean isManaged() {
		 if(this.entity != null) 
			 return	!entity.isNew();
		 return false;
	}
	
	@Override
	public boolean isEditing() {
		return isManaged();
	}
	
	@Override
	public String showCreate() {
//		createBean();
//		updateCancelView();		
		return facadePath(createFileName());
	}

	@Override
	public String showUpdate() {
//		if(entity == null)
//			return facadePath(ERROR_ACTION);
//		editing = true;
//		updateCancelView();
		return facadePath(editFileName());
	}

	@Override
	public String showSearch() {
//		this.input = null;
//		beforeSearch();
		return facadePath(searchFileName());
	}

	@Override
	public String showDelete() {
//		if(entity == null)
//			return facadePath(ERROR_ACTION);
//		editing = true;
//		updateCancelView();
		return facadePath(removeFileName());
	}

	@Override
	public void setCancelView(String cancelView) {
		this.cancelView = cancelView;
	}

	@Override
	public String getCancelView() {
		return cancelView;
	}

	@Override
	public String getPersistReturnView() {
		return persistReturnView;
	}

	@Override
	public void setPersistReturnView(String persistReturnView) {
		this.persistReturnView = persistReturnView;
	}

	protected String searchFileName() {
		return INDEX_ACTION;
	}

	protected String createFileName() {
		return CREATE_ACTION;
	}
	protected String editFileName() {
		return EDIT_ACTION;
	}
	protected String removeFileName() {
		return REMOVE_ACTION;
	}
	
	protected String facadePath(String action){
		return JSFMenuUtil.buildMenuPath(userRolePath(), entityPrefix(), action);
	}
	


	@Override
	public String persist() {
//		beforePersist();
		
    	GenericDao<T, PK> dao = getDao();
		if(dao == null)
			throw new java.lang.IllegalStateException("DAO not Injected");

		try{
			if(isManaged()){
				if(logger.isLoggable(Level.FINE))
					logger.fine("Updating: " + entity);
//				beforeUpdate();
				dao.merge(entity);
//				afterUpdate();
			}else{
				if(logger.isLoggable(Level.FINE))
					logger.fine("Creating new Entity of Type: " + entity.getClass().getSimpleName());
//				beforeCreate();
//				if(validateBeforCreate()){
					dao.persist(entity);					
//					afterCreate();
//				}else{
//					validateError();
//					return currentView();
//				}
			}
		}catch (Exception e) {
			FacesUtil.addErrorMessage(e.getLocalizedMessage());			
//			return currentView();
		}	
		
//		afterPersist();
		conversation.end();
		
		return showSearch();//persistOk();
	}
	
	@Override
	public String delete() {
//		beforeRemove();
		
		GenericDao<T, PK> dao = getDao();
		if(dao == null)
			throw new java.lang.IllegalStateException("DAO not Injected");
		if(logger.isLoggable(Level.FINE))
			logger.fine("Removing " + getClass().getSimpleName() + " with Id: " + getEntityId());
    	try {
//    		if(!hasDependencies()){
//    			if(removeEntityDependencies()){
	    			dao.remove(entity);
//	    			afterRemove();    			
//	    			return removeOk();
//    			}
//    		}
//    		return removeCancel();
		} catch (Exception e) {
			FacesUtil.addErrorMessage(e.getLocalizedMessage());
//	    	return removeError();
		}
    	conversation.end();
    	return showSearch();//Esto no vá
	}
	
	
	@Override
	public void refresh(){
		if(logger.isLoggable(Level.FINE))
			logger.fine("Refreshing Entity: " + entity);
		try {
			setEntity(getDao().findById(getEntityId()));
		} catch (Exception e) {
			FacesUtil.addErrorMessage(e.getLocalizedMessage());
		}
	}	
	
	@Override
	public String cancel() {
		conversation.end();
		return showSearch();
	}

	public void initConversation() {
		if (conversation.isTransient()) {
			conversation.begin();
		}
	}	
	
	@Override
	public List<T> getAllEntities(){
		GenericDao<T, PK> dao = getDao();
		if(dao == null)
			throw new java.lang.IllegalStateException("DAO not Injected");
        try {
			return dao.findAll();
		} catch (Exception e) {
			FacesUtil.addErrorMessage(e.getLocalizedMessage());
		}
        return null;
	}
	
	
	/*
	 * Template Methods
	 */
	protected abstract GenericDao<T, PK> getDao();
	protected abstract T newEntity();
	
	protected T loadEntity() {
		GenericDao<T, PK> dao = getDao();
		if(dao == null)
			throw new java.lang.IllegalStateException("null Dao");
		if(this.id == null)
			throw new java.lang.IllegalStateException("Can't load entity with null id");
		try {
			return getDao().findById(this.id);
		} catch (DaoException e) {
		}
		return null;
	}

	protected PK getEntityId(){
		return getEntityId(getEntity());
	}
	
	protected abstract PK getEntityId(T t);
	
	protected String entityPrefix(){
		ParameterizedType parameterizedType = (ParameterizedType) getClass()
				.getGenericSuperclass();
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) parameterizedType.getActualTypeArguments()[0];
		return beanNameFromClass(clazz);
	}
	
	protected abstract String userRolePath();
	
	private String beanNameFromClass(final Class<T> beanClass) {
		String classname = beanClass.getName();
		int index = classname.lastIndexOf('.');
		classname = Character.toLowerCase(classname.charAt(index + 1)) + classname.substring(index + 2);

		return classname;
	}	

	
}
